package com.bening.smsapp.downloader;

import com.bening.smsapp.filechangereg.DataFetchProcess; 
import com.bening.smsapp.exception.ChangeWorkingDirectoryFailedException;
import com.bening.smsapp.bean.*;
import com.bening.smsapp.bootstrap.BootConfigParameters;
import com.bening.smsapp.constant.SmsAppConstant;
import com.bening.smsapp.exception.SmsAppException;
import com.bening.smsapp.exception.FtpLoginFailedException;
import com.bening.smsapp.factory.SmsAppFactory;
import com.bening.smsapp.util.*;

import java.util.*;
import org.apache.commons.net.MalformedServerReplyException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.sql.Connection;
import java.sql.SQLException;

public class FtpClient
{
    private FTPClient ftpClient = null;
    private static Logger logger = Logger.getLogger( FtpClient.class);
    BootConfigParameters params = BootConfigParameters.getInstance();

    /**
     * constructor, setup an Ftp object.
     */
    public FtpClient()
    {
        this.ftpClient = new FTPClient();
    }

    /**
     * connect and login to ftp server using specified port.
     * @param host
     * @param port
     */
    public void login( String host, int port, String username, String password )
            throws FtpLoginFailedException
    {
        final Logger logger = Logger.getLogger( getClass() );
        

        try
        {

            ftpClient.connect( host, port );

            if ( logger.isInfoEnabled() )
            {
                logger.info( "login using username '" + username + "' with password " + password );
            }

       
            boolean loggedIn = ftpClient.login( username, password );
           
            if( !loggedIn )
            {
                throw new FtpLoginFailedException( "username or password don't match" );
            }
           
        }
        catch( SocketException e )
        {
        	logger.error("ftp login failed SocketException..",e);
        }
        catch( MalformedServerReplyException e  )
        {
        	logger.error("ftp login failed MalformedServerReplyException..",e);
        }
        catch( IOException e )
        {
        	logger.error("ftp login failed IOException..",e);
            
        }
        
        String replyString;
        if( ftpClient != null )
        {
            replyString = ftpClient.getReplyString();
        }
        else
        {
            throw new FtpLoginFailedException( "null ftpClient reply string." );
        }

        if( replyString != null )
        {
            logger.info( "login ok, reply: " + replyString  + "\nconnected to server " + host + ":" + port );
        }
        else
        {
        	SmsAppTools.InsertEventLog(SmsAppConstant.DOWNLOAD_ERROR, "Failed to login to remote FTP host "+host,0);
        	throw new FtpLoginFailedException( "failed to login to remote FTP host." );
        }
    }


    /**
     * download files that appears in the database.
     */
    public void downloadRegisteredList( PathSource p, MachineSource m, BootConfigParameters params)
            throws SmsAppException
    {
        final Logger logger = Logger.getLogger( getClass() );
        final String METHOD_SIGNATURE = "[ftp]";

        if( p.getPathDir() == null )
        {
            throw new SmsAppException( METHOD_SIGNATURE + "null folder not allowed." );
        }

        DataFetchProcess process   = DataFetchProcess.getInstance();

        if ( logger.isInfoEnabled() )
        {
            logger.debug( METHOD_SIGNATURE + "get list of files to be downloaded." );
        }

        List filesToDownload = process.getToBeDownloadedList(m,p);

        try
        {
            if ( logger.isInfoEnabled() )
            {
                logger.info( "set working directory to: " + p.getPathDir() );
            }

            ftpClient.changeWorkingDirectory( p.getPathDir() );
        }
        catch ( IOException e )
        {
            
            logger.error( e.getMessage() );
            SmsAppTools.InsertEventLog(SmsAppConstant.DOWNLOAD_ERROR, e.getMessage(), p.getPathSourceId());
            throw new SmsAppException( e.getMessage() );
        }

        int listSize = filesToDownload.size();
        if( listSize > 0 )
        {
            if ( logger.isInfoEnabled() )
            {
                logger.info( METHOD_SIGNATURE + "iterates list of files to be downloaded." );
            }

            Connection conn = SmsAppFactory.getDbConnection();

            for( int i = 0; i < listSize; i++ )
            {
            	FileSource f = (FileSource) filesToDownload.get(i);
            	String filename = f.getFileName();

                if ( logger.isInfoEnabled() )
                {
                    logger.info( METHOD_SIGNATURE + "BEGIN downloading file " + filename );
                }

                try
                {
                    SmsAppTools.updateFileStatus( filename, SmsAppConstant.FLAG_PARSE_READY);
                }
                catch ( SQLException e )
                {
                    logger.error( METHOD_SIGNATURE + "SQLException: " + e.getMessage(), e );
                    SmsAppTools.InsertEventLog(SmsAppConstant.SQL_ERROR, e.getMessage(), p.getPathSourceId());
                    continue; // skip this for loop
                }

                
                File file = new File( p.getLocalPathDir()+File.separator+filename );
                FileOutputStream fos;
                try
                {
                    fos = new FileOutputStream( file );
                }
                catch ( FileNotFoundException e )
                {
                    logger.error( "FileNotFoundException: " + e.getMessage(), e );

                    if ( logger.isInfoEnabled() )
                    {
                        logger.info( "skipping file '" + filename + "' due to exception occured." );
                    }

                    continue; // skip this for loop
                }

                boolean result;

                try
                {
                    if ( logger.isInfoEnabled() )
                    {
                        logger.info( "TRYING TO download: " + filename );
                    }
                    ftpClient.setFileTransferMode(ftpClient.STREAM_TRANSFER_MODE);
                    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                    result = ftpClient.retrieveFile( filename, fos );
                    if( fos != null )
                    {
                        fos.close();
                    }
                }
                catch ( IOException e )
                {
                    logger.error( "IOException: " + e.getMessage(), e );

                    if ( logger.isInfoEnabled() )
                    {
                        logger.info( "skipping file '" + filename + "' due to exception occured." );
                    }

                    continue; // skip this for loop
                }

  /*              try
                {*/
                    if( !result )
                    {
                        logger.error( "Error while retrieving file '" + filename + "'." );
                        // restore the status back for ready to download.
                        SmsAppTools.InsertEventLog(SmsAppConstant.DOWNLOAD_ERROR, "Error while retrieving file '" + filename + "'.", p.getPathSourceId());
                    }
                    else
                    {
                        // SmsAppTools.updateFileStatus( filename, FileChangeRegConstant.FLAG_WAIT_FOR_PARSING, FileChangeRegConstant.FLAG_DOWNLOADING, conn );
                    }
/*                }
                catch ( SQLException e )
                {
                    logger.error( "SQLException: " + e.getMessage(), e );
                }*/
               /* finally
                {
                    try
                    {
                        conn.close();
                    }
                    catch ( SQLException e )
                    {
                        logger.error( "SQLException: while closing database connection: " + e.getMessage(), e );
                    }
                }*/

                if ( logger.isInfoEnabled() )
                {
                    logger.debug( METHOD_SIGNATURE + "END: finished downloading file " + filename );
                }
            }
            /* trying */
            try
            {
            	logger.info("closing");
                conn.close();
            }
            catch ( SQLException e )
            {
                logger.error( "SQLException: while closing database connection: " + e.getMessage(), e );
            }
        }
        else
        {
            if ( logger.isInfoEnabled() )
            {
                logger.debug( METHOD_SIGNATURE + "no files to be downloaded." );
            }
        }
    }


    /**
     * get file list from specified remoteDir
     * @return List list of files in the specified remoteDir.
     */
    public List getFileList( PathSource p, BootConfigParameters params) throws SmsAppException
    {
        final Logger logger = Logger.getLogger( getClass() );
        final String METHOD_SIGNATURE = "[ftp]";

        if( p.getPathDir() == null )
        {
            throw new SmsAppException( METHOD_SIGNATURE + "null remoteDir not allowed." );
        }
 
        FTPFile[] files = null;

        try
        {
            boolean resultOk = ftpClient.changeWorkingDirectory( p.getPathDir() );
            if( !resultOk )
            {
            	SmsAppTools.InsertEventLog(SmsAppConstant.DOWNLOAD_ERROR, "failed to change working directory, probably invalid remote directory: '" + p.getPathDir() + "'", p.getPathSourceId());
                throw new ChangeWorkingDirectoryFailedException( "failed to change working directory, probably invalid remote directory: '" + p.getPathDir() + "'" );
            }

            files = ftpClient.listFiles();
            

            if ( logger.isInfoEnabled() )
            {
                logger.info( METHOD_SIGNATURE + "found " + files.length + " file(s)." );
            }
        }
        catch ( IOException e )
        {
            logger.error( "IOException: " + e.getMessage(), e );
        }

        List result = new ArrayList();

        if ( files != null )
        {
            // add all file names from the list
            int arraySize = files.length;
            
            for ( int i = 0; i < arraySize; i++ )
            {
                FTPFile ftpFile = files[i];

                // add files only, do not include directory entries
                if( !ftpFile.isDirectory() )
                {
                	// filtered
                	if(ftpFile.getName().indexOf(p.getFileNamePattern())!=-1) {
                		FileSource f = new FileSource();
                		f.setFileName(ftpFile.getName());
                		f.setFileSize(ftpFile.getSize());
                		f.setDownloadedTime(new Date());
                		f.setSourcePathId(p.getPathSourceId());
                		f.setLocalFilePath(p.getLocalPathDir());
                		f.setCdrType(p.getCdrType());
                		result.add( f );
                	}
                }
            }
        }

        return result;
    }

    /**
     * logout from the remote FTP host.
     */
    public void logout() throws SmsAppException
    {
        try
        {
            ftpClient.logout();
            ftpClient.disconnect();
        }
        catch ( IOException e )
        {
           // logger.error( "IOException: when logging out. " + e.getMessage(), e );
            //throw new SmsXtraException( "failed when logging out." );
        }
        catch(Exception e) {
        	logger.error("Other Exception " + e.getMessage(), e);
        }
    }
    
   /* public static void main(String[] args ) {
    	FtpClient ftp = new FtpClient();
    	System.out.println("FTP");
    	try {
    		ftp.login("172.30.202.57",21,"root","jatis05");
    		List l = ftp.getFileList("/smsxtra/localcopy");
    		System.out.println("Size : "+l.size());
    	}catch (SmsXtraException sx) {
    		sx.printStackTrace();
    	}
    }*/
}

